package com.game.manager;

import java.util.ArrayList;
import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import java.util.Observable;
import java.util.Observer;

import org.phprpc.util.PHPSerializer;

import com.game.base.SimulationObject;
import com.game.base.SobFactory;
import com.game.database.MysqlHelper;
import com.mysql.jdbc.Blob;
import com.mysql.jdbc.BlobFromLocator;

public class SobManager implements Observer {

	private static SobManager instance;
	public static SobManager get(){
		if(instance == null)
		{
			instance = new SobManager();
		}
		return instance;
	}
	
	//缓存所有查询对象
	private Hashtable<Integer, SimulationObject> allobjs = new Hashtable<Integer, SimulationObject>();
	
	//记录所有对象的更新时间，如果超过12个小时没有更新的对象，就从allobjs的缓存里面清楚掉
	private Hashtable<Integer, Long> objupdates = new Hashtable<Integer, Long>(); 
	
	public SobManager(){
		instance = this;
	}
	
	public SimulationObject createSob(String classname,int parentid){
		SimulationObject sob = SobFactory.create(classname);
		sob.pid = parentid;
		sob.children = new ArrayList<Integer>();
		try {
			byte[] rs = new PHPSerializer().serialize(sob);
			Object[] obj = new Object[1];
			obj[0] = rs;
			sob.id = MysqlHelper.ExecuteInsert("insert into obj_item (`data`) values (?)", obj);
			if(parentid>0)
			{
				SimulationObject parent = getSob(parentid);
				parent.children.add(sob.id);
				this.updateSob(parent);
			}
			updateSob(sob);
			sob.addObserver(this);
			objupdates.put(sob.id, new Date().getTime());
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
		allobjs.put(sob.id, sob);
		return sob;
	}
	
	/**
	 * 复制出一个新的对象
	 * @param target
	 * @param parentid
	 * @return
	 */
	public SimulationObject cloneSob(SimulationObject target, int parentid){
		try {
			byte[] rs = new PHPSerializer().serialize(target);
			SimulationObject sob = (SimulationObject)new PHPSerializer().unserialize(rs);
			sob.pid = parentid;
			Object[] obj = new Object[1];
			obj[0] = rs;
			sob.id = MysqlHelper.ExecuteInsert("insert into obj_item (`data`) values (?)", obj);
			if(parentid>0)
			{
				SimulationObject parent = getSob(parentid);
				parent.children.add(sob.id);
				this.updateSob(parent);
			}
			updateSob(sob);
			sob.addObserver(this);
			objupdates.put(sob.id, new Date().getTime());
			allobjs.put(sob.id, sob);
			return sob;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	
	/**
	 * 获取子对象
	 * @param parentid 父对象的id
	 * @param filters null表示获取所有子对象，classname字符串集合，只获取过滤的这些子
	 * @return
	 */
	public List<SimulationObject> getChilds(int parentid,String[] filters){
		SimulationObject parent = getSob(parentid);
		List<SimulationObject> list = new ArrayList<SimulationObject>();
		if(parent.children.size()>0){
			for(Integer id : parent.children){
				SimulationObject obj = getSob(id);
				for(String cn : filters){
					if(obj.getClass().getName().equals(cn)){
						list.add(obj);
						break;
					}
				}
			}
			return list;
		}
		else
			return null;
	}
	/**
	 * 获取子对象
	 * @param parentid 父对象的id
	 * @param depth 表示子的深度，儿子的儿子都要
	 * @param filters 表示获取所有子对象，classname字符串集合，只获取过滤的这些子
	 * @return
	 */
	public List<SimulationObject> getChilds(int parentid,int depth,String[] filters){
		if(depth==0){
			return null;
		}
		SimulationObject parent = getSob(parentid);
		List<SimulationObject> list = new ArrayList<SimulationObject>();
		if(parent.children.size()>0){
			for(Integer id : parent.children){
				SimulationObject obj = getSob(id);
				for(String cn : filters){
					if(obj.getClass().getName().equals(cn)){
						list.add(obj);
						List<SimulationObject> sublist = getChilds(obj.id, depth-1, filters);
						if(sublist != null){
							for(SimulationObject subobj : sublist){
								list.add(subobj);
							}
						}
						break;
					}
				}
			}
			return list;
		}
		else
			return null;
	}
	
	public SimulationObject getSob(int id){
		if(this.allobjs.containsKey(id)){
			updatecache(id);
			return this.allobjs.get(id);
		} else {
			Object[] params = new Object[1];
			params[0] = id;
			try {
				Object data = MysqlHelper.ExecuteScalar("select data from obj_item where id = ?", params);
				if(data!=null){
					byte[] bs = (byte[])data;
					Object obj = new PHPSerializer().unserialize(bs);
					SimulationObject ret = (SimulationObject)obj;
					ret.addObserver(this);
					this.updatecache(ret.id);
					return ret;					
				}
				else
				{
					return null;
				}
			} catch (Exception e) {
				e.printStackTrace();
				return null;
			}
		}
	}
	public boolean deleteSob(int id){
		SimulationObject parentobj=null;
		SimulationObject obj = null;
		if(this.allobjs.containsKey(id)){
			obj = this.allobjs.get(id);
			parentobj= this.allobjs.get(obj.pid);
			obj.deleteObservers();
			if(this.allobjs.containsKey(id)){
				this.allobjs.remove(id);
			}	
		}
		try {
			if(obj == null){
				obj = getSob(id);
			}
			if(parentobj == null && obj.pid>0){
				parentobj = getSob(obj.pid);
				if(parentobj.children.contains(obj.id)){
					parentobj.children.remove((Object)obj.id);
					updateSob(parentobj);
				}
			}
			Object[] objs = new Object[1];
			objs[0] = id;
			MysqlHelper.ExecuteNoneQuery("delete from obj_item where id = ?", objs);
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}
	
	public void cacheClear(){
		Enumeration<Integer> el = this.objupdates.keys();
		long curtime = new Date().getTime();
		while(el.hasMoreElements()){
			int id = el.nextElement();
			long time = this.objupdates.get(id);
			if(time-curtime>12*3600000){
				this.allobjs.remove(id);
				this.objupdates.remove(id);
			}
		}
	}
	
	private void updatecache(int id){
		this.objupdates.put(id, new Date().getTime());
	}
	
	public void updateSob(SimulationObject sob){
		try {
			byte[] rs = new PHPSerializer().serialize(sob);
			Object[] objs = new Object[2];
			objs[0] = rs;
			objs[1] = sob.id;
			MysqlHelper.ExecuteNoneQuery("update obj_item set data = ? where id = ?", objs);			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public void update(Observable obj, Object arg) {
		if(obj instanceof SimulationObject){
			try {
				this.updateSob((SimulationObject) obj);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
}
